/* Copyright (C) 2003  All Rights Reserved.  */

#ifndef _PACOS_CLI_H
#define _PACOS_CLI_H

#include "modbmap.h"
#include "cli_mode_types.h"
#include "cfg_data_types.h"

/* CLI macro.  Macro defines a CLI structure and a CLI function.  C99
   C preprocessor variadic macros is used to define arbitrary number
   of help string definition.  */

/* Perl script is used for extracting CLI and ALI macro from source
   code.  In that case EXTRACT_CLI should be defined to prevent macro
   expansion.  */

#ifndef EXTRACT_CLI

#ifdef HAVE_ISO_MACRO_VARARGS
#define CLI(func_name, cli_name, cmd_str, ...)                          \
                                                                        \
/* Function prototype.  */                                              \
int func_name (struct cli *, int, char**);                              \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {__VA_ARGS__, NULL};                        \
                                                                        \
/* Define CLI structure.  */                                            \
struct cli_element cli_name =                                           \
{                                                                       \
  /* Command line string.  */                                           \
  cmd_str,                                                              \
                                                                        \
   /* Function pointer.  */                                             \
  func_name,                                                            \
                                                                        \
  /* Help string is defined as an array.  Last must be NULL.  */        \
  cli_name ## _help                                                     \
};                                                                      \
                                                                        \
/* Start function body at here.  */                                     \
int func_name (struct cli *cli, int argc, char** argv)

/* ALIAS to CLI macro.  Define CLI structure only.  There is no
   function body.  */
#define ALI(func_name, cli_name, cmd_str, ...)                          \
                                                                        \
extern int func_name (struct cli *cli, int argc, char** argv);          \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {__VA_ARGS__, NULL};                        \
                                                                        \
struct cli_element cli_name =                                           \
{                                                                       \
  cmd_str,                                                              \
  func_name,                                                            \
  cli_name ## _help                                                     \
}

/* IMI/IMISH ALI generated by cli.pl for IMI and IMIsh.  */
#define IMI_ALI(func_name, cli_name, cmd_str, ...)                      \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {__VA_ARGS__, NULL};                        \
                                                                        \
struct cli_element cli_name =                                           \
{                                                                       \
  cmd_str,                                                              \
  func_name,                                                            \
  cli_name ## _help                                                     \
}

#else

#define CLI(func_name, cli_name, cmd_str, ARGS...)                      \
                                                                        \
/* Function prototype.  */                                              \
int func_name (struct cli *, int, char**);                              \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {##ARGS, NULL};                             \
                                                                        \
/* Define CLI structure.  */                                            \
struct cli_element cli_name =                                           \
{                                                                       \
  /* Command line string.  */                                           \
  cmd_str,                                                              \
                                                                        \
   /* Function pointer.  */                                             \
  func_name,                                                            \
                                                                        \
  /* Help string is defined as an array.  Last must be NULL.  */        \
  cli_name ## _help                                                     \
};                                                                      \
                                                                        \
/* Start function body at here.  */                                     \
int func_name (struct cli *cli, int argc, char** argv)

/* ALIAS to CLI macro.  Define CLI structure only.  There is no
   function body.  */
#define ALI(func_name, cli_name, cmd_str, ARGS...)                      \
                                                                        \
extern int func_name (struct cli *cli, int argc, char** argv);          \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {##ARGS, NULL};                             \
                                                                        \
struct cli_element cli_name =                                           \
{                                                                       \
  cmd_str,                                                              \
  func_name,                                                            \
  cli_name ## _help                                                     \
}

/* IMI/IMIsh ALI generated by cli.pl for IMI and IMIsh.  */
#define IMI_ALI(func_name, cli_name, cmd_str, ARGS...)                  \
                                                                        \
/* Help string array.  */                                               \
char *cli_name ## _help[] = {##ARGS, NULL};                             \
                                                                        \
struct cli_element cli_name =                                           \
{                                                                       \
  cmd_str,                                                              \
  func_name,                                                            \
  cli_name ## _help                                                     \
}

#endif /* HAVE_ISO_MACRO_VARARGS. */
#endif /* EXTRACT_CLI */

/* CLI output function.  We can switch over CLI output function
   defining cli->out_func.  */

typedef int (*CLI_OUT_FUNC) (void *, char *, ...);

/* CLI output function macro.  Instead of defining a function, user
   can specify CLI output function dynamically.  */
#ifdef HAVE_ISO_MACRO_VARARGS
#define cli_out(cli, ...)                                                     \
        (*(cli)->out_func)((cli)->out_val, __VA_ARGS__)
#else
#define cli_out(cli, ARGS...)                                                 \
        (*(cli)->out_func)((cli)->out_val, ##ARGS)
#endif /* HAVE_ISO_MACRO_VARARGS. */

/* CLI parsing tree.  This structure has all of CLI commands and run
   time variables such as mode and privilege.  Mode and privilege
   level will be passed to cli_parse() function then set to this
   structure.  */

struct cli_tree
{
  /* Current mode.  */
  int mode;

  /* Privilege level.  */
  u_char privilege;

  /* Vector of modes.  */
  vector modes;

  /* Vector of configuration output function.  */
  vector config_write;

  /* Node to be executed.  */
  struct cli_node *exec_node;

  /* Possibly matched cel.  Function internal use only.  */
  vector v;

  /* Traverse nodes. */
  vector t;

  /* Expand is needed.  Used by describe function.  */
  int expand_node;

  /* Show node match result.  */
  int show_node;

  /* Used to suppress the default paging of a nested show command. */
  bool_t nested_show;

  /* Parsed argc and argv.  */
  int argc;
#define CLI_ARGC_MAX               128
#define CLI_ARGV_MAX_LEN           256
  char *argv[CLI_ARGC_MAX];

  /* For Output Modifier.  */
  struct cli_node *modifier_node;
  int argc_modifier;
  char *argv_modifier[CLI_ARGC_MAX];
  char *rem;

  /* Parse failed character pointer to show invalid input.  */
  char *invalid;

  /* To show pipe pointer.  */
  char *pipe;

  /* Advanced mode.  */
  int advanced;
};

/* Argument to cli functions.  */
struct cli
{
  /* CLI element.  */
  struct cli_element *cel;

  /* User input string.  */
  char *str;

  /* Output function to be used by cli_out().  */
  CLI_OUT_FUNC out_func;

  /* Output function's first argument.  */
  void *out_val;

  /* Arbitrary information for line.  */
  void *line;

  /* Auth required.  */
  int auth;

  /* Input source.  */
  int source;
#define CLI_SOURCE_USER                 0
#define CLI_SOURCE_FILE                 1

  /* For "line". */
  int line_type;
  int min;
  int max;

  /* Real CLI.  */
  void *index;
  void *index_sub;
  int mode;

  /* Current CLI status.  */
  enum {
    CLI_NORMAL,
    CLI_CLOSE,
    CLI_MORE,
    CLI_CONTINUE,
    CLI_MORE_CONTINUE,
    CLI_WAIT
  } status;

  /* Flags. */
  u_char flags;
#define CLI_FROM_PVR    (1 << 0)

  void *self;
  u_char privilege;
  struct cli_tree *ctree;

  /* Global variable.  */
  struct lib_globals *zg;
  struct apn_vr *vr;

  /* Terminal length.  */
  int lines;

  /* Call back function.  */
  int (*callback) (struct cli *);
  int (*cleanup) (struct cli *);
  s_int32_t (*show_func) (struct cli *);
  int type;
  u_int32_t count;
  void *current;
  void *arg;
  afi_t afi;
  safi_t safi;

#ifdef HAVE_CUSTOM1
  /* L2 handling.  */
  u_int64_t port_range;
#endif /* HAVE_CUSTOM1 */

  /* Vector used by IMI to encode a single CLI command string.
   */
  cfg_vect_t *cv;
};

/* Configuration output function.  */

typedef int (*CLI_CONFIG_FUNC) (struct cli *cli);

/* CLI element.  */
struct cli_element
{
  /* Command line string.  */
  char *str;

  /* Function to execute this command.  */
  int (*func) (struct cli *, int, char **);

  /* Help strings array. */
  char **help;

  /* Unique key. */
  int key;

  /* Flags of the commands.  */
  u_int16_t flags;

  /* When CLI_FLAG_HIDDEN is defined, the command isn't used for
     completion.  */
#define CLI_FLAG_HIDDEN            (1 << 0)

  /* When CLI_FLAG_MODIFIER is define, output modifier '|' can be used
     for the command.  Usually the flag is set to show commands.  */
#define CLI_FLAG_MODIFIER          (1 << 1)

  /* This is only used by struct cli_node.  When the node is "show" or
     "*s=show" this flag should be set.  */
#define CLI_FLAG_SHOW              (1 << 2)

  /* This is only used by struct cli_node.  When the node is in
     parenthesis this flag is set.  */
#define CLI_FLAG_PAREN             (1 << 3)

  /* This node is in brace.  */
#define CLI_FLAG_TRAVERSE          (1 << 4)

  /* This node is recursive.  */
#define CLI_FLAG_RECURSIVE         (1 << 5)

  /* Execute CLI function before send it to IMI.  */
#define CLI_FLAG_LOCAL_FIRST       (1 << 6)

  /* This enforce not apply the pager to the output.  */
#define CLI_FLAG_NO_PAGER          (1 << 7)

  /* This flag is used for interface name match.  */
#define CLI_FLAG_IFNAME            (1 << 8)

  /* This is only used by WMI (Web Management Interface). */
#define CLI_FLAG_WMI               (1 << 9)

  /* Set if ignore PM command error is required at the IMI level. */
  /* NOTE: Generally, if a command is sent to PM and the PM is down
           or not responsive, the IMI returns and error to the IMISH,
           and the command is aborted.
           This works in all the cases, where the IMI does not process
           the same commands as PM, except CLI mode change.
           In other cases, when the IMI executes the same command as the protocol
           daemon - e.g. "hostname WORD" goes to the ISIS (host.c) and IMI -
           we need to ignore the error when the PM is down so the IMI can
           process it. The IMISH will not get the "PM down" error.
   */

#define CLI_FLAG_IGN_PM_DOWN_ERR   (1 << 10)

  /* Send this command to all on the list, regardless of failures returned by some. */
#define CLI_FLAG_MCAST   (1 << 11)

#define CLI_PLUS_SIGN_FORBIDDEN   (1 << 12)

  /* Protocol module to which this command belongs. */
  modbmap_t module;

  /* This is the conifguration data type the command will
     deliver to the IMI module. For use only by IMI module.
   */
//  cfgDataType_e data_type;
   u_int16_t data_type;

  /* This is the mode which the CLI will switch into, if the
     mode change command completes successfully.
   */
  u_int16_t     new_mode;
};

/* CLI tree node.  */
struct cli_node
{
  /* CLI token types.  */
  enum cli_token
    {
      cli_token_paren_open,
      cli_token_paren_close,
      cli_token_cbrace_open,
      cli_token_cbrace_close,
      cli_token_brace_open,
      cli_token_brace_close,
      cli_token_ifname_open,
      cli_token_ifname_close,
      cli_token_separator,
      cli_token_pipe,
      cli_token_redirect,
      cli_token_dot,
      cli_token_question,
      cli_token_range,
      cli_token_keyword,
      cli_token_alias,
      cli_token_line,
      cli_token_word,
      cli_token_ipv4,
      cli_token_ipv4_prefix,
      cli_token_ipv6,
      cli_token_ipv6_prefix,
      cli_token_time,
      cli_token_community,
      cli_token_mac_address,
      cli_token_ifname,
      cli_token_unknown
    } type;

  /* String to be matched.  */
  char *str;

  /* Help string.  */
  char *help;

  /* Max and min.  */
  u_int32_t max;
  u_int32_t min;

  /* Pointer to CLI element.  */
  struct cli_element *cel;

  /* Vector of next nodes.  */
  vector keywords;

  /* Privilege node.  */
  u_char privilege;

  /* Same as cli_element's flags.  */
  u_int16_t flags;

  /* Reference count.  */
  u_int32_t refcnt;
};

/* Return value.  */
#define CLI_SUCCESS           0
#define CLI_ERROR             1
#define CLI_AUTH_REQUIRED     2
#define CLI_EOL               3

/* Privilege level.  */
#define PRIVILEGE_MIN         1
#define PRIVILEGE_VR_MAX     15
#define PRIVILEGE_PVR_MAX    16

#define PRIVILEGE_NORMAL        PRIVILEGE_MIN
#ifdef HAVE_VR
#define PRIVILEGE_MAX           (PRIVILEGE_PVR_MAX)
#define PRIVILEGE_ENABLE(V)                                                   \
    ((V)->id == 0 ? PRIVILEGE_PVR_MAX : PRIVILEGE_VR_MAX)
#else /* HAVE_VR */
#define PRIVILEGE_MAX           (PRIVILEGE_VR_MAX)
#define PRIVILEGE_ENABLE(V)     (PRIVILEGE_VR_MAX)
#endif /* HAVE_VR */

/* Max length of each token.  */
#define MAX_TOKEN_LENGTH   256

#define MODULE_ID2MODE(MODULE_ID)                                             \
    ((MODULE_ID) == APN_PROTO_RIP    ? RIP_MODE    :                          \
     (MODULE_ID) == APN_PROTO_RIPNG  ? RIPNG_MODE  :                          \
     (MODULE_ID) == APN_PROTO_OSPF   ? OSPF_MODE   :                          \
     (MODULE_ID) == APN_PROTO_OSPF6  ? OSPF6_MODE  :                          \
     (MODULE_ID) == APN_PROTO_ISIS   ? ISIS_MODE   :                          \
     (MODULE_ID) == APN_PROTO_BGP    ? BGP_MODE    :                          \
     (MODULE_ID) == APN_PROTO_LDP    ? LDP_MODE    :                          \
     (MODULE_ID) == APN_PROTO_RSVP   ? RSVP_MODE   :                          \
     (MODULE_ID) == APN_PROTO_PIMDM  ? PDM_MODE    :                          \
     (MODULE_ID) == APN_PROTO_PIMSM  ? PIM_MODE    :                          \
     (MODULE_ID) == APN_PROTO_OAM    ? BFD_MODE    :                          \
     (MODULE_ID) == APN_PROTO_LMP    ? LMP_MODE    :                          \
     (MODULE_ID) == APN_PROTO_PIMSM6 ? PIM6_MODE   :                          \
     (MODULE_ID) == APN_PROTO_DVMRP  ? DVMRP_MODE  :                          \
     (MODULE_ID) == APN_PROTO_8021X  ? AUTH8021X_MODE :                       \
     (MODULE_ID) == APN_PROTO_ONM    ? ONMD_MODE   :                          \
     (MODULE_ID) == APN_PROTO_ELMI   ? ELMI_MODE   :                          \
     (MODULE_ID) == APN_PROTO_STP    ? STP_MODE    :                          \
     (MODULE_ID) == APN_PROTO_RSTP   ? RSTP_MODE   :                          \
     (MODULE_ID) == APN_PROTO_MSTP   ? MSTP_MODE   :                          \
     (MODULE_ID) == APN_PROTO_RMON   ? RMON_MODE   : PAL_FALSE)

/* CLI parser result codes.  */
#define CLI_PARSE_SUCCESS             0
#define CLI_PARSE_INCOMPLETE          1
#define CLI_PARSE_INCOMPLETE_PIPE     2
#define CLI_PARSE_EMPTY_LINE          3
#define CLI_PARSE_AMBIGUOUS           4
#define CLI_PARSE_NO_MATCH            5
#define CLI_PARSE_NO_MODE             6
#define CLI_PARSE_ARGV_TOO_LONG       7

/* Common descriptions. */
#define CLI_IFNAME_STR  "Interface name"
#define CLI_TELINK_NAME_STR  "TE Link name"
#define CLI_CCNAME_STR  "Control Channel name"
#define CLI_CANAME_STR  "Control Adjacency name"
#define CLI_SHOW_STR "Show running system information"
#define CLI_STATS_STR "Statistics"
#define CLI_SHOW_MEMORY_STR  "Memory information"
#define CLI_SHOW_BRIDGE_STR  "Bridge information"
#define CLI_NO_STR "Negate a command or set its defaults"
#define CLI_WRITE_STR "Write running configuration to memory, file or terminal"
#define CLI_CLEAR_STR "Reset functions"
#define CLI_FIB_STR "FIB information"
#define CLI_IP_STR "Internet Protocol (IP)"
#define CLI_ARP_STR "Address Resolution Protocol (ARP)"
#define CLI_IPV6_STR "Internet Protocol version 6 (IPv6)"
#define CLI_IMI_STR "Integrated Management Interface (IMI)"
#define CLI_NSM_STR "Network Service Module (NSM)"
#define CLI_NSM_MCAST_STR "IPv4 multicast"
#define CLI_NSM_MCAST6_STR "IPv6 multicast"
#define CLI_RIP_STR "Routing Information Protocol (RIP)"
#define CLI_RIPNG_STR "Routing Information Protocol (RIP) for IPv6"
#define CLI_OSPF_STR "Open Shortest Path First (OSPF)"
#define CLI_OSPF6_STR "Open Shortest Path First (OSPF) for IPv6"
#define CLI_OSPF6_IF_STR "OSPFv3 interface commands"
#define CLI_ISIS_STR "Intermediate System - Intermediate System (IS-IS)"
#define CLI_CLNS_STR "Connectionless-Mode Network Service (CLNS)"
#define CLI_BGP_STR "Border Gateway Protocol (BGP)"
#define CLI_8021X_STR "IEEE 802.1X Port-Based Access Control"
#define CLI_ONMD_STR "LLDP and EFM_OAM"
/*MAC-based auth Enhancement*/
#define CLI_MAC_AUTH_STR "APN MAC-Based Authentication"
#define CLI_LACP_STR "Link Aggregation Control Protocol (LACP)"
#define CLI_GVRP_STR "GARP VLAN Registration Protocol (GVRP)"
#define CLI_GMRP_STR "GARP Multicast Registration Protocol (GMRP)"
#define CLI_STP_STR "Spanning Tree Protocol (STP)"
#define CLI_RSTP_STR "Rapid Spanning Tree Protocol (RSTP)"
#define CLI_MSTP_STR "Multiple Spanning Tree Protocol (MSTP)"
#define CLI_RPVST_STR "Rapid PerVlan Spanning Tree Protocol (RPVST)"
#define CLI_CFM_STR "Connectivity Fault Management Protocol (CFM)"
#define CLI_MPLS_STR "Multi-Protocol Label Switching (MPLS)"
#define CLI_MPLS_CMD_STR "Multi-Protocol Label Switching (MPLS)"
#define CLI_LDP_STR  "Label Distribution Protocol (LDP)"
#define CLI_RSVP_STR "Resource Reservation Protocol (RSVP)"
#define CLI_IGMP_STR "Internet Group Management Protocol (IGMP)"
#define CLI_IGMP_SNOOP_STR "Layer 2 Snooping"
#define CLI_MLD_STR "Multicast Listener Discovery (MLD)"
#define CLI_MLD_SNOOP_STR "Layer 2 Snooping"
#define CLI_PIM_STR "Protocol Independent Multicast (PIM)"
#define CLI_PIMSM_STR "Sparse Mode (PIM-SM)"
#define CLI_PIMDM_STR "Dense Mode (PIM-DM)"
#define CLI_PIM6_STR "Protocol Independent Multicast (PIM) for IPv6"
#define CLI_PIMSM6_STR "Sparse Mode (PIM-SM) for IPv6"
#define CLI_PIMDM6_STR "Dense Mode (PIM-DM) for IPv6"
#define CLI_DVMRP_STR "Distance Vector Multicast Routing Protocol (DVMRP)"
#define CLI_NEIGHBOR_STR "Specify a neighbor router"
#define CLI_AF_STR "Address family"
#define CLI_AFM_STR "Address family modifier"
#define CLI_DEBUG_STR "Debugging functions (see also 'undebug')"
#define CLI_UNDEBUG_STR "Disable debugging functions (see also 'debug')"
#define CLI_UNDEBUG_ALL_STR "Turn off all Debugging"
#define CLI_ROUTER_STR "Enable a routing process"
#define CLI_AS_STR "AS number"
#define CLI_MATCH_STR "Match values from routing table"
#define CLI_SET_STR "Set values in destination routing protocol"
#define CLI_OUT_STR "Filter outgoing routing updates"
#define CLI_IN_STR  "Filter incoming routing updates"
#define CLI_V4NOTATION_STR "specify by IPv4 address notation(e.g. 0.0.0.0)"
#define CLI_INTERFACE_STR "Interface information"
#define CLI_SECONDS_STR "<1-65535> Seconds"
#define CLI_ROUTE_STR "Routing Table"
#define CLI_PREFIX_LIST_STR "Build a prefix list"
#define CLI_CLEAR_PREFIX_LIST_STR "Clear a prefix list"
#define CLI_VRF_STR "VPN Routing/Forwarding instance"
#define CLI_VRF_DISP_STR "Display routes from a VPN Routing/Forwarding instance"
#define CLI_VRF_NAME_STR "VPN Routing/Forwarding instance name"
#define CLI_VR_STR "Virtual-router configuration"
#define CLI_VR_NAME_STR "Virtual-router name" " (max " VAR_SUPERSTR (LIB_VR_MAX_NAMELEN) " characters)"
#define CLI_VR_ID_STR "Virtual Router ID"
#define CLI_VR_EXPORT_STR "Export routes between virtual-routers"
#define CLI_ND_STR "IPv6 interface Neighbor Discovery subcommands"
#define CLI_MIP_STR "Mobile IP"
#define CLI_HA_STR "Home agent"
#define CLI_NAT_STR "Network Address Translation (NAT)"
#define CLI_TUNNEL_STR "protocol-over-protocol tunneling"
#define CLI_TUNNEL_MODE_STR "tunnel encapsulation method"
#define CLI_FILTER_STR "Firewall"
#define CLI_ACCESS_GROUP_STR "Access Group "
#define CLI_GMPLS_STR "Generalized MPLS (GMPLS)"
#define CLI_GMPLS_LINK_ID_STR "Link Local/Remote Identifiers"
#define CLI_GMPLS_LINK_PROP_STR "Link Properties"
#define CLI_GMPLS_PROTECTION_TYPE_STR "Link Protection Type"
#define CLI_GMPLS_CAPABILITY_STR "Switching Capability Type"
#define CLI_GMPLS_ENCODING_TYPE_STR "LSP Encoding"
#define CLI_GMPLS_MIN_LSP_BW_STR "Minimum LSP Bandwidth"
#define CLI_GMPLS_MAX_LSP_SIZE_STR "Maximum LSP Size"
#define CLI_GMPLS_SDH_INDICATION_STR "SONET/SDH Indication"
#define CLI_GMPLS_RISK_GROUP_STR "Shared Risk Link Group"
#define CLI_GMPLS_INTERFACE_TYPE_STR "Interface Type"
#define CLI_GMPLS_LOCAL_INTERFACE_ID_STR "Local Interface Identifier"
#define CLI_GMPLS_REMOTE_INTERFACE_ID_STR "Remote Interface Identifier"
#define CLI_GMPLS_REMOTE_INTERFACE_ID_STR "Remote Interface Identifier"
#define CLI_DATA_LINK_STR "Data Link"
#define CLI_TE_LINK_STR "TE Link"
#define CLI_CTRL_CHNL_STR "Control Channel"
#define CLI_CTRL_ADJ_STR "Control Adjacency"
#define CLI_LOCAL_LINK_ID_STR "Local Link Identifier"
#define CLI_REMOTE_LINK_ID_STR "Local Link Identifier"
#define CLI_CTRL_CHNL_PARAM_STR "Control Channel Parameters"
#define CLI_CTRL_ADJ_PARAM_STR "Control Adjacency Parameters"
#define CLI_DHCP_STR "Dynamic Host Configuration Protocol (DHCP)"
#define CLI_PPPOE_STR "Point-to-Point over Ethernet (PPPoE)"
#define CLI_VRRP_STR "Virtual Router Redundancy Protocol (VRRP)"
#define CLI_KEY_STR "Authentication key management"
#define CLI_CHAIN_STR "Key-chain management"
#define CLI_KEYSTRING_STR "Set key string"
#define CLI_KEYCHAIN_ACCEPT_LIFETIME_STR "Set accept lifetime of the key"
#define CLI_KEYCHAIN_SEND_LIFETIME_STR "Set send lifetime of the key"
#define CLI_ROUTEMAP_STR "Create route-map or enter route-map command mode"
#define CLI_ACCESS_STR "Add an access list entry"
#define CLI_ACCESS_GRP_STR "Add an access group entry"
#define CLI_ACCESS_LIST_NAME_STR "Access-list name"
#define CLI_ACCESS_PACOS_STR "IP PacOS access-list name"
#define CLI_ACCESS6_PACOS_STR "IPv6 PacOS access-list name"
#define CLI_ACCESS_PERMIT_STR "Specify packets to forward"
#define CLI_ACCESS_DENY_STR "Specify packets to reject"
#define CLI_PREFIX_LIST_NAME_STR "Name of a prefix list"
#define CLI_PREFIX_NETWORK_STR "IP prefix <network>/<length>, e.g., 35.0.0.0/8"
#define CLI_PREFIX6_NETWORK_STR "IPv6 prefix <network>/<length>, e.g., 3ffe::/16"
#define CLI_PREFIX_LENGTH_MIN "Minimum prefix length"
#define CLI_PREFIX_LENGTH_MAX "Maximum prefix length"
#define CLI_PREFIX_LENGTH_MIN_MATCH "Minimum prefix length to be matched"
#define CLI_PREFIX_LENGTH_MAX_MATCH "Maximum prefix length to be matched"
#define CLI_PREFIX_SEQ_STR "Sequence number of an entry"
#define CLI_PREFIX_SEQNUM_STR "Sequence number"
#define CLI_DISTRIBUTE_LIST_STR "Filter networks in routing updates"
#define CLI_DISTRIBUTE_PREFIX_STR "Filter prefixes in routing updates"
#define CLI_DISTRIBUTE_IN_STR "Filter incoming routing updates"
#define CLI_DISTRIBUTE_OUT_STR "Filter outgoing routing updates"
#define CLI_USER_STR "User management"
#define CLI_USER_NAME_STR "User login name"
#define CLI_VLAN_STR "Add, delete, or modify values associated with a single VLAN"
#define CLI_RMON_STR "Remote Monitoring Protocol (RMON)"

#define CONFIG_MPLS_STR    "Configure MPLS specific attributes"
#define NO_CONFIG_MPLS_STR "Unset MPLS specific attributes"
#define SHOW_MPLS_STR      "Show MPLS specific data"
#define CLEAR_MPLS_STR     "Clear MPLS specific data"

#define CONFIG_VPLS_STR    "Configure VPLS specific attributes"
#define NO_CONFIG_VPLS_STR "Unset VPLS specific attributes"
#define CLI_MTRACE_SRC_STR "Source to trace route from"
#define CLI_MTRACE_DST_STR "Destination of multicast trace"
#define CLI_MTRACE_GRP_STR "Group for multicast trace or 0.0.0.0"
#define CLI_MTRACE_TTL_STR "Time-To-Live for multicast trace request"
#define CLI_MTRACE_STR "Trace multicast path from source to destination"
#define CLI_MSTAT_STR "Show statistics after multiple multicast traceroutes"

/* CPU Database related strings */
#define CLI_STACKING_STR "Switch box Stacking"
#define CLI_STACK_NUM_CPU_STR "Number of CPUs in the system"
#define CLI_STACK_DB_STR "Number of CPUs in the Database"
#define CLI_STACK_MASTER_DEV_STR "Master CPU Device in the Database"
#define CLI_PW_MODE_STR          "PW mode configure"//fxg
#define CLI_VPN_MODE_STR          "VPN mode configure"//fxg
#define CLI_LSP_MODE_STR          "LSP mode configure"//fxg
#define CLI_LSP_GRP_MODE_STR          "LSP protect group mode configure"//djg
#define CLI_LSP_OAM_MODE_STR          "LSP oam mode configure"//djg
#define CLI_PTP_MODE_STR          "PTP mode configure"//djg
#define CLI_PTP_PORT_MODE_STR          "PTP port configure"//djg

#define CLI_AC_MODE_STR          "AC mode configure"//fxg
#define CLI_TUN_MODE_STR         "Tunnel mode configure"//fxg
#define CLI_MEG_MODE_STR          "MEG mode configure"//fxg
#define CLI_RPORT_MODE_STR          "RPORT mode configure"//fxg
#define CLI_OAM_1731_MODE_STR          "OAM_1731 mode configure"//fxg
#define CLI_SEC_MODE_STR          "Sec mode configure"//fxg

/*
 * The following macros are used when
 * the CLI used for deleting a entry is provided with only mandatory parameters.
 */
#define CLI_MIN_PARAMS_ENTRY_DELETE             0
#define CLI_MAX_PARAMS_ENTRY_DELETE             1

#ifdef HAVE_RSVPD
#define PRI_STR            "Configure primary LSP option"
#define SEC_STR            "Configure secondary LSP option"
#define NO_PRI_STR         "Unset primary LSP option"
#define NO_SEC_STR         "Unset secondary LSP option"
#endif /* HAVE_RSVPD */

#ifdef HAVE_IPV6
#define NEIGHBOR_CMD       "neighbor (A.B.C.D|X:X::X:X) "
#define NO_NEIGHBOR_CMD    "no neighbor (A.B.C.D|X:X::X:X) "
#define NEIGHBOR_ADDR_STR  "IP address","IPv6 address"
#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|X:X::X:X|WORD) "
#define NEIGHBOR_ADDR_STR2 "Neighbor address","Neighbor IPv6 address","Neighbor tag"
#else
#define NEIGHBOR_CMD       "neighbor A.B.C.D "
#define NO_NEIGHBOR_CMD    "no neighbor A.B.C.D "
#define NEIGHBOR_ADDR_STR  "IP address"
#define NEIGHBOR_CMD2      "neighbor (A.B.C.D|WORD) "
#define NO_NEIGHBOR_CMD2   "no neighbor (A.B.C.D|WORD) "
#define NEIGHBOR_ADDR_STR2 "Neighbor address","Neighbor tag"
#endif /* HAVE_IPV6 */

#ifdef HAVE_BFD
#define CLI_BFD_STRING         "Bidirectional Forwarding Detection (BFD)"
#define CLI_BFD_CMD_STR        "Bidirectional Forwarding Detection (BFD)"
#define CLI_BFD_DISABLE_CMD_STR        "Disable BFD"
#define CLI_BFD_FALL_OVER_CMD_STR      "Fall-over detection"
#define CLI_BFD_ALL_INTERFACES_CMD_STR "Enable BFD on all interfaces"
#define CLI_BFD_STATIC_ALL_INTERFACES_CMD_STR  "Enable static BFD on all interfaces"
#endif /* HAVE_BFD */

#ifdef HAVE_LMP
#define CLI_LMP_STR             "Link Management Protocol (LMP)"
#define CLI_LMP_CMD_STR         "Link Management Protocol (LMP)"
#endif /* HAVE_LMP */

/* Multicast static route CLI strings */
#define CLI_MROUTE_STR      "Configure static multicast routes"

#ifdef HAVE_ELMID
#define CLI_ELMI_STR  "Ethernet Local Management Interface Protocol (ELMI)"
#endif /* HAVE_ELMID */

#ifdef HAVE_PBR
#define  CLI_POLICY_STR  "apply routemap policy on interface"
#endif /* HAVE_PBR */

/* Allocate a new CLI stree.  */

struct cli_tree *cli_tree_new ();

int cli_parse (struct cli_tree *, int, u_char, char *, int, int);
void cli_describe (struct cli *, struct cli_tree *, int cli_mode, u_char,
                   char *, int);
char **cli_complete (struct cli_tree *, int cli_mode, u_char, char *);

int cli_install_gen (struct cli_tree *, int cli_mode, u_char, u_int16_t,
                     struct cli_element *);
int cli_install (struct cli_tree *, int cli_mode, struct cli_element *);
int cli_install_hidden (struct cli_tree *, int cli_mode,
                        struct cli_element *);

int cli_install_imi (struct cli_tree *,
                     int cli_mode,
                     modbmap_t,
                     u_char,
                     u_int16_t,
                     struct cli_element *);

void
cli_set_imi_cmd (struct cli_element *cel,
                 int           new_mode,
                 cfgDataType_e data_type);

void cli_install_shortcut (struct cli_tree *, int cli_mode, char *, char *,
                           char *);

int cli_install_config (struct cli_tree *, int, CLI_CONFIG_FUNC func);

void cli_set_node_flag (struct cli_tree *, int, char *,
                        u_int16_t);
void cli_sort (struct cli_tree *);
void cli_free_arguments (struct cli_tree *);

void cli_mode_exit (struct cli *);
void cli_install_default (struct cli_tree *, int);
void cli_install_default_family (struct cli_tree *, int);

char *cli_interface_resolve (char *, int, char *, char *);

const char *cli_mode_str (int);
const char *cli_prompt_str (int);

/* Utility function.  */
char *argv_concat (char **, int, int);
int cmd_str2int (char *, int *);
int cli_mask_check (struct pal_in4_addr);
char * cli_skip_white_space(char *cmd_str);


#define CLI_INSTALL(Z, M, PM, C)                                              \
    do {                                                                      \
      if ((Z)->protocol == APN_PROTO_IMI)                                     \
        cli_install_imi ((Z)->ctree, M, PM, PRIVILEGE_NORMAL, 0, C);          \
      else                                                                    \
        cli_install_gen ((Z)->ctree, M, PRIVILEGE_NORMAL, 0, C);              \
    } while (0)

#define CLI_INSTALL_HIDDEN(Z, M, PM, C)                                       \
    do {                                                                      \
      if ((Z)->protocol == APN_PROTO_IMI)                                     \
        cli_install_imi ((Z)->ctree, M, PM, PRIVILEGE_NORMAL,                 \
                         CLI_FLAG_HIDDEN, C);                                 \
      else                                                                    \
        cli_install_gen ((Z)->ctree, M, PRIVILEGE_NORMAL, CLI_FLAG_HIDDEN, C);\
    } while (0)

#define CLI_GET_INTEGER(NAME,V,STR)                                           \
    do {                                                                      \
      int retv;                                                               \
      (V) = cmd_str2int ((STR), &retv);                                       \
      if (retv < 0)                                                           \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_INTEGER_RANGE(NAME,V,STR,MIN,MAX)                             \
    do {                                                                      \
      int retv;                                                               \
      (V) = cmd_str2int ((STR), &retv);                                       \
      if (retv < 0 || (V) < (MIN) || (V) > (MAX))                             \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_INTEGER64(NAME,V,INT,STR,MIN,MAX)                             \
    do {                                                                      \
      int retv;                                                               \
      int val = 0;                                                            \
      (V) = cmd_str2int ((STR), &retv);                                       \
      pal_mem_cpy (&INT.l[0], &val, 4);                                       \
      pal_mem_cpy (&INT.l[1], &(V), 4);                                       \
      if (retv < 0 || (V) < (MIN) || (V) > (MAX))                             \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_UINT32(NAME,V,STR)                                            \
    do {                                                                      \
      int retv;                                                               \
      if (pal_strncmp ((STR), "-", 1) == 0)                                   \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
      (V) = cmd_str2int ((STR), &retv);                                       \
      if (retv < 0)                                                           \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_UINT32_RANGE(NAME,V,STR,MIN,MAX)                              \
    do {                                                                      \
      char *endptr = NULL;                                                    \
      (V) = pal_strtou32 ((STR), &endptr, 10);                                \
      if (*endptr != '\0' || ((u_int32_t)(MIN) > 0                            \
          && (V) < (u_int32_t)(MIN))                                          \
          || (V) > (u_int32_t)(MAX))                                          \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_IPV4_ADDRESS(NAME,V,STR)                                      \
    do {                                                                      \
      int retv;                                                               \
      retv = pal_inet_pton (AF_INET, (STR), &(V));                            \
      if (!retv)                                                              \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_IPV4_PREFIX(NAME,V,STR)                                       \
    do {                                                                      \
      int retv;                                                               \
      retv = str2prefix_ipv4 ((STR), &(V));                                   \
      if (retv <= 0)                                                          \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#ifdef HAVE_IPV6
#define CLI_GET_IPV6_ADDRESS(NAME,V,STR)                                      \
    do {                                                                      \
      int retv;                                                               \
      retv = pal_inet_pton (AF_INET6, (STR), &(V));                           \
      if (!retv)                                                              \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#define CLI_GET_IPV6_PREFIX(NAME,V,STR)                                       \
    do {                                                                      \
      int retv;                                                               \
      retv = str2prefix_ipv6 ((STR), &(V));                                   \
      if (retv <= 0)                                                          \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)
#endif /* HAVE_IPV6 */

#define CLI_GET_RMAP_ORIGIN(NAME,V,ARGC,STR)                                  \
    do {                                                                      \
      if ((ARGC) == 0)                                                        \
        (V) = NULL;                                                           \
      else if (pal_strncmp ((STR), "ig", 2) == 0)                             \
        (V) = "igp";                                                          \
      else if (pal_strncmp ((STR), "e", 1) == 0)                              \
        (V) = "egp";                                                          \
      else if (pal_strncmp ((STR), "in", 2) == 0)                             \
        (V) = "incomplete";                                                   \
      else                                                                    \
        {                                                                     \
          cli_out (cli, "%% Invalid %s value\n", NAME);                       \
          return CLI_ERROR;                                                   \
        }                                                                     \
    } while (0)

#endif /* _PACOS_CLI_H */
